home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Tool Chest / Testing & Debugging / Virtual User / Virtual User Current Release / Examples / Example External Tools / ProcessTool / RequestDispatcher.cp < prev    next >
Encoding:
Text File  |  1998-06-04  |  17.5 KB  |  678 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    File:        RequestDispatcher.cp
  3.  *
  4.  *    Contains:    xxx put contents here xxx
  5.  *
  6.  *    Written by:    Rick Violet
  7.  *
  8.  *    Copyright:    © 1992-1994 by Apple Computer, Inc., all rights reserved.
  9.  *
  10.  *    Change History (most recent first):
  11.  *
  12.  *         <7>     1/28/94    CMW        String utilities have moved to TextUtils.h.
  13.  *         <2>     4/15/93    RV        Fix Memory Leak in DispatchCustomRequest
  14.  *                11/18/92    RV        xxx put comment here xxx
  15.  *
  16.  *    To Do:
  17.  */
  18.  
  19. #include <PLStringFuncs.h>
  20. #include <SysEqu.h>
  21. #include <Strings.h>
  22. #include <TextUtils.h>
  23.  
  24. #ifndef        __MEMORY__
  25. #include        <Memory.h>
  26. #endif        __MEMORY__
  27.  
  28. #ifndef        __RESOURCES__
  29. #include        <Resources.h>
  30. #endif        __RESOURCES__
  31.  
  32. #ifndef        __GESTALTEQU__
  33. #include        <GestaltEqu.h>
  34. #endif        __GESTALTEQU__
  35.  
  36. #ifndef        __Application__
  37. #include        "Application.h"
  38. #endif        __Application__
  39.  
  40. #ifndef        __RequestDispatcher__
  41. #include        "RequestDispatcher.h"
  42. #endif        __RequestDispatcher__
  43.  
  44. #ifndef        __ProcessServices__
  45. #include        "ProcessServices.h"
  46. #endif        __ProcessServices__
  47.  
  48. //—————————————————————————————————————————————————————————————————————————————————————
  49. //                                Global Variables
  50. //—————————————————————————————————————————————————————————————————————————————————————
  51.         RequestDispatcher*        gTheRequestDispatcher;
  52. extern    Application*            gTheApplication;
  53.  
  54. //—————————————————————————————————————————————————————————————————————————————————————
  55. //                                External Routines
  56. //—————————————————————————————————————————————————————————————————————————————————————
  57. extern    void    TerminalError(short errResID, short errCode);    
  58.  
  59. //—————————————————————————————————————————————————————————————————————————————————————
  60. //    RequestDispatcher::RequestDispatcher    -    constructor.
  61. //—————————————————————————————————————————————————————————————————————————————————————
  62. RequestDispatcher::RequestDispatcher()
  63. {
  64.     const    long    gestaltAppleEventsManager101 = 1;
  65.     
  66.     OSErr    tErr;
  67.     long    tGestaltResult;
  68.  
  69.     fRequestQueue = nil;
  70.     fServices = nil;
  71.     fReqBeingProcessed = nil;
  72.     fRunningInSystem7 = false;
  73.     
  74.         //————    Construct a Queue for incoming requests
  75.     fRequestQueue = new List();
  76.     if( fRequestQueue == nil )
  77.     {
  78.         TerminalError( kDispatcherErrStrings, kReqQueueConstructErr );
  79.     }
  80.         
  81.         //————    Construct a Queue for Services
  82.     fServices = new List();
  83.     if( fServices == nil )
  84.     {
  85.         TerminalError( kDispatcherErrStrings, kServQueueConstructErr );
  86.     }
  87.     
  88.     
  89.         //————    Determine if we're running Post System 6 system software
  90.     if( Gestalt( gestaltSystemVersion, &tGestaltResult) == noErr )
  91.     {
  92.         fRunningInSystem7 = ( tGestaltResult >= 7 ); 
  93.     }
  94.  
  95.         //————    Make sure that AppleEvents are availible, in the right version
  96.     tErr = Gestalt( gestaltAppleEventsAttr, &tGestaltResult);
  97.     
  98.         //————    Check the gestaltAppleEventsPresent bit
  99.     if( !(tGestaltResult & ( 1 << gestaltAppleEventsPresent )) )
  100.     {
  101.         TerminalError( kDispatcherErrStrings, kAppleEventVersionErr );
  102.     }
  103.  
  104.         //————    Check the gestaltAppleEventsManager101 bit
  105.     if( !(tGestaltResult & ( 1 << gestaltAppleEventsManager101 )) )
  106.     {
  107.         TerminalError( kDispatcherErrStrings, kAppleEventVersionErr );
  108.     }
  109.  
  110.         //————    Install all the Request Handlers
  111.     ConstructAllServiceObjects();
  112. }
  113.  
  114. //—————————————————————————————————————————————————————————————————————————————————————
  115. //    RequestDispatcher::~RequestDispatcher    -    destructor.
  116. //—————————————————————————————————————————————————————————————————————————————————————
  117. RequestDispatcher::~RequestDispatcher()
  118. {
  119.         //————    Delete all the Service Objects
  120.     if( fServices )
  121.     {
  122.         fServices->DisposeAll();
  123.         delete fServices;
  124.     }
  125.     
  126.         //————    Delete all the Queued Requests
  127.     if( fRequestQueue )
  128.     {
  129.         fRequestQueue->DisposeAll();
  130.         delete fRequestQueue;
  131.     }
  132.         
  133. }
  134.  
  135. //—————————————————————————————————————————————————————————————————————————————————————
  136. //    RequestDispatcher::ConstructAllServices    -    Install all the Service objects.
  137. //
  138. //        This method calls the constructor for each Request handler
  139. //        and installs a pointer to it in the Queue of Services
  140. //
  141. //        You must construct and install your Custom Request Handlers here 
  142. //—————————————————————————————————————————————————————————————————————————————————————
  143. void
  144. RequestDispatcher::ConstructAllServiceObjects()
  145. {
  146.     Service*    tService;
  147.     
  148.         //————    if the List for containing the services does not exist,
  149.         //————    bail out so we don't crash.
  150.     if( fServices == nil )
  151.     {
  152.         return;
  153.     }
  154.     
  155.         //————    Construct the service object : ProcessNamesListService
  156.     tService =  new ProcessNamesListService();
  157.     if( tService )
  158.     {
  159.         fServices->AddAsLast( tService );
  160.     }
  161.  
  162.         //————    Construct the service object : FrontProcessNameService
  163.     tService =  new FrontProcessNameService();
  164.     if( tService )
  165.     {
  166.         fServices->AddAsLast( tService );
  167.     }
  168.  
  169.         //————    Construct the service object : PartitionSizeService
  170.     tService =  new PartitionSizeService();
  171.     if( tService )
  172.     {
  173.         fServices->AddAsLast( tService );
  174.     }
  175.  
  176.         //————    Construct the service object : FreeMemService
  177.     tService =  new FreeMemService();
  178.     if( tService )
  179.     {
  180.         fServices->AddAsLast( tService );
  181.     }
  182.  
  183.         //————    Construct the service object : ReadByteService
  184.     tService =  new ReadByteService();
  185.     if( tService )
  186.     {
  187.         fServices->AddAsLast( tService );
  188.     }
  189.  
  190.         //————    Construct the service object : ReadBlockService
  191.     tService =  new ReadBlockService();
  192.     if( tService )
  193.     {
  194.         fServices->AddAsLast( tService );
  195.     }
  196.  
  197. }
  198.  
  199. //—————————————————————————————————————————————————————————————————————————————————————
  200. //    RequestDispatcher::DoOneRequest    - Process first pending Request in the queue.
  201. //—————————————————————————————————————————————————————————————————————————————————————
  202. void
  203. RequestDispatcher::DoOneRequest()
  204. {
  205.     Request*    tReq;
  206.     
  207.         //————    Is there an element in the Queue?
  208.     if( (fRequestQueue != nil) && (fRequestQueue->Count() > 0) )
  209.     {
  210.             //————    Reset any TimeOut counters which need it
  211.         ResetAllTimeOutCounters();
  212.         
  213.             //————    there is a Request in the Queue
  214.             //————    Extract it from the Queue
  215.         tReq = (Request*)fRequestQueue->GetFirst();
  216.  
  217.             //————    if we got a Request object
  218.         if( tReq )
  219.         {
  220.             fRequestQueue->Remove( tReq );
  221.         
  222.                 //————    Keep track of which request is currently
  223.                 //————    being processed, so it can be canceled if needed
  224.             fReqBeingProcessed = tReq;
  225.             
  226.                 //————    Process the request
  227.             if( !tReq->HasBeenCanceled() )
  228.             {
  229.                 ProcessRequest( tReq );
  230.             }
  231.             tReq->SendResult();
  232.             delete tReq;
  233.  
  234.                 //————    No longer processing this request
  235.             fReqBeingProcessed = nil;
  236.         }
  237.     }
  238. }
  239.  
  240. //—————————————————————————————————————————————————————————————————————————————————————
  241. //    RequestDispatcher::QueueRequest    -    Puts a Request into our Queue
  242. //—————————————————————————————————————————————————————————————————————————————————————
  243. void
  244. RequestDispatcher::QueueRequest( Request* pReq )
  245. {
  246.         //————    if this is a request to cancel a service request,
  247.         //————    then find the service request and cancel it
  248.     if( pReq->IsACancelRequest() )
  249.     {
  250.         DoCancelReq( pReq );
  251.         delete pReq;
  252.     }
  253.     else
  254.     {
  255.             //————    This is not a request to cancel a service request
  256.             //————    so queue it up, for processing later
  257.         if( fRequestQueue != nil )
  258.         {
  259.             fRequestQueue->AddAsLast( pReq );
  260.         }
  261.     }
  262. }
  263.  
  264. //—————————————————————————————————————————————————————————————————————————————————————
  265. //    RequestDispatcher::CancelCurrentRequest    - Cancel processing of the current request
  266. //—————————————————————————————————————————————————————————————————————————————————————
  267. void
  268. RequestDispatcher::CancelCurrentRequest()
  269. {
  270.     Request*    tReq;
  271.     
  272.     tReq = GetCurrentRequest();
  273.     if( tReq != nil )
  274.     {
  275.         tReq->CancelThisRequest();
  276.     }
  277. }
  278.  
  279. //—————————————————————————————————————————————————————————————————————————————————————
  280. //    RequestDispatcher::ProcessRequest    -    Process the Request
  281. //—————————————————————————————————————————————————————————————————————————————————————
  282. void
  283. RequestDispatcher::ProcessRequest( Request* pReq )
  284. {
  285.     char*    tServiceName;
  286.  
  287.         //————    Get the Text of the Service requested
  288.     tServiceName = pReq->GetWhichService();
  289.  
  290.         //————    Check for GetToolVersion request
  291.     if( relstring( tServiceName, (char*)kVUAEGetToolVersion, false, true ) == 0 )
  292.     {
  293.         DoGetToolVersReq( pReq );
  294.         return;
  295.     }
  296.  
  297.         //————    Check for GetToolServices request
  298.     if( relstring( tServiceName, (char*)kVUAEGetServiceList, false, true ) == 0 )
  299.     {
  300.         DoGetToolServicesReq( pReq );
  301.         return;
  302.     }
  303.  
  304.         //————    Check for GetToolServices request
  305.     if( relstring( tServiceName, (char*)kVUAEHasService, false, true ) == 0 )
  306.     {
  307.         DoServiceSupportedReq( pReq );
  308.         return;
  309.     }
  310.     
  311.         //————    Check for Initialize request
  312.     if( relstring( tServiceName,(char*)kVUAEInitialize, false, true ) == 0 )
  313.     {
  314.         DoInitializeReq();
  315.         return;
  316.     }
  317.     
  318.         //————    Check for Quit request
  319.     if( relstring( tServiceName,(char*)kVUAEQuitService, false, true ) == 0 )
  320.     {
  321.         gTheApplication->DoMenuCommand( kFileMenuID, kQuitItem );
  322.         return;
  323.     }
  324.     
  325.     DispatchCustomRequest( pReq );
  326.  
  327.     return;
  328.  
  329. }
  330.  
  331. //—————————————————————————————————————————————————————————————————————————————————————
  332. //    RequestDispatcher::DoCancelReq    -    do the cancel Request
  333. //—————————————————————————————————————————————————————————————————————————————————————
  334. void
  335. RequestDispatcher::DoCancelReq( Request* pReq )
  336. {
  337.     Loop*            tLoop;
  338.     Request*    tSrvReq;
  339.     
  340.         //————    Are we currently processing another request?
  341.     if( CurrentlyProcessingARequest() )
  342.     {
  343.             //————    We are currently processing a request,
  344.             //————    Check to see if the current request is the one to be canceled
  345.         tSrvReq = GetCurrentRequest();
  346.         if( tSrvReq->IsCancelRequestForThisRequest( pReq ) )
  347.         {
  348.             tSrvReq->CancelThisRequest();
  349.             return;
  350.         }
  351.     }
  352.  
  353.         //————    Now check the Queue for the Request that this cancel is for.
  354.     tLoop = new Loop( fRequestQueue );
  355.     if( tLoop )
  356.     {
  357.         while( tSrvReq = (Request*)(tLoop->GetNext()) )
  358.         {
  359.                 //————    Is this the Service Object to be canceled?
  360.             if( tSrvReq->IsCancelRequestForThisRequest( pReq ) )
  361.             {
  362.                 tSrvReq->CancelThisRequest();
  363.                 return;
  364.             }
  365.     
  366.         }
  367.         delete tLoop;
  368.     }
  369.  
  370.     
  371.         //————    if it was not found, then it was either never received,
  372.         //————    or was completed and returned before the cancel request
  373.         //————    arrived. In either case, just return an empty return value.
  374. }
  375.  
  376. //—————————————————————————————————————————————————————————————————————————————————————
  377. //    RequestDispatcher::DoGetToolVersReq    -    return the version information
  378. //—————————————————————————————————————————————————————————————————————————————————————
  379. void
  380. RequestDispatcher::DoGetToolVersReq( Request* pReq )
  381. {
  382.     VUList*            tReturnList;
  383.     char            tText[256];
  384.     
  385.     tReturnList = new VUList();
  386.     if( tReturnList )
  387.     {
  388.             //————    Get the Tool's Name
  389.         GetToolName( tText );
  390.         tReturnList->PutNthItem( tText );
  391.         
  392.             //————    Get the Tool's Version String
  393.         GetToolVersionString( tText );
  394.         tReturnList->PutNthItem( tText );
  395.  
  396.         pReq->SetReturnValue( tReturnList );
  397.     }
  398.     else
  399.     {
  400.         pReq->SetErrorCode( memFullErr );
  401.         pReq->SetErrorMessage( "Out of memory?" );
  402.     }
  403. }
  404.  
  405. //—————————————————————————————————————————————————————————————————————————————————————
  406. //    RequestDispatcher::DoInitializeReq    -    pass initialize message to all services
  407. //—————————————————————————————————————————————————————————————————————————————————————
  408. void
  409. RequestDispatcher::DoInitializeReq()
  410. {
  411.     Loop*            tLoop;
  412.     Service*        tService;
  413.  
  414.         //————    Scan through the Service objects, 
  415.         //————    and inform it that we have received and initialize messagge
  416.     tLoop = new Loop( fServices );
  417.     if( tLoop )
  418.     {
  419.         while( tService = (Service*)(tLoop->GetNext()) )
  420.         {
  421.                 //————    Call the initialize method for the service object
  422.             tService->Initialize();
  423.         }
  424.     }
  425.     delete tLoop;
  426. }
  427.  
  428. //—————————————————————————————————————————————————————————————————————————————————————
  429. //    RequestDispatcher::DispatchCustomRequest    -    execute a custom Request
  430. //—————————————————————————————————————————————————————————————————————————————————————
  431. void
  432. RequestDispatcher::DispatchCustomRequest( Request* pReq )
  433. {
  434.     Loop*        tLoop;
  435.     Service*    tService;
  436.     char*        tServiceName;
  437.  
  438.         //————    Get the Text of the Service requested
  439.     tServiceName = pReq->GetWhichService();
  440.     
  441.     
  442.     if( fServices == nil )
  443.     {
  444.             //————    no queue object, bail out
  445.         return;
  446.     }
  447.     
  448.     tLoop = new Loop( fServices );
  449.     if( tLoop )
  450.     {
  451.         while( tService = (Service*)(tLoop->GetNext()) )
  452.         {
  453.                 //————    Is this the Service Object which can handle this request?
  454.             if( tService->CanDoService( tServiceName ) )
  455.             {
  456.                     //————    This is the correct Service Object,
  457.                     //————    Get the service object to process the request
  458.                 tService->ProcessRequest( pReq );
  459.                     
  460.                     //————    Reset the cursor, so beach ball is not left there
  461.                 InitCursor();
  462.                 delete tLoop;
  463.                 return;
  464.             }
  465.         }
  466.         delete tLoop;
  467.     }
  468.         
  469.         //————    The service which handles this request was not found
  470.         //————    Report error and return
  471.     pReq->SetErrorCode( errAEUnknownService );
  472.     pReq->SetErrorMessage( "Service not found" );
  473. }
  474.  
  475. //—————————————————————————————————————————————————————————————————————————————————————
  476. //    RequestDispatcher::DoGetToolServicesReq    -    return the list of Request names
  477. //—————————————————————————————————————————————————————————————————————————————————————
  478. void
  479. RequestDispatcher::DoGetToolServicesReq( Request* pReq )
  480. {
  481.     Loop*            tLoop;
  482.     VUList*            tReturnList;
  483.     Service*        tService;
  484.     ScriptValue*    tReturnNames;
  485.     ScriptValue*    tVal;
  486.     char*            tText;
  487.     ValueKind        tVKind;
  488.     short            tLastElement;
  489.     short            i;
  490.     
  491.     tReturnList = new VUList();
  492.     
  493.     if( tReturnList )
  494.     {
  495.             //————    Scan through the Service objects, and collect the
  496.             //————    text of the service names which this tool supports
  497.         tLoop = new Loop( fServices );
  498.         if( tLoop )
  499.         {
  500.             while( tService = (Service*)(tLoop->GetNext()) )
  501.             {
  502.                     //————    Get the service's Name text
  503.                     //————    and append it to the list
  504.                 tReturnNames = tService->GetServiceNameText();
  505.                 if( tReturnNames )
  506.                 {
  507.                     switch( tReturnNames->GetValueKind() )
  508.                     {
  509.                         case kVUListKind:
  510.                         {
  511.                             tLastElement = ((VUList*)tReturnNames)->GetCount();
  512.                             for( i = 1; i < tLastElement; i++ )
  513.                             {
  514.                                 tVKind = kVUStringKind;
  515.                                 ((VUList*)tReturnNames)->GetNthItem( i, tVal, tVKind );
  516.                                 if( tVal )
  517.                                 {
  518.                                     tText = ((VUString*)tVal)->GetText();
  519.                                     tReturnList->PutNthItem( tText );
  520.                                 }
  521.                             }
  522.                         }
  523.                         break;
  524.                         
  525.                         default:
  526.                         {
  527.                             tText = ((VUString*)tReturnNames)->GetText();
  528.                             tReturnList->PutNthItem( tText );
  529.                         }
  530.                         break;
  531.                         
  532.                     }
  533.                     delete tReturnNames;
  534.                 }
  535.             }
  536.             delete tLoop;
  537.         }
  538.  
  539.             //————    We have tranversed the entire list of service objects
  540.             //————    and collected each service's name into the list
  541.             //————    now return the list to V.U.
  542.         pReq->SetReturnValue( tReturnList );
  543.     }
  544. }
  545.  
  546. //—————————————————————————————————————————————————————————————————————————————————————
  547. //    RequestDispatcher::DoServiceSupportedReq    -    return the list of Request names
  548. //—————————————————————————————————————————————————————————————————————————————————————
  549. void
  550. RequestDispatcher::DoServiceSupportedReq( Request* pReq )
  551. {
  552.     Loop*            tLoop;
  553.     Service*        tService;
  554.     ScriptValue*    tParam;
  555.     char*            tSrvText;
  556.     ValueKind        tVKind;
  557.     OSErr            tErr;
  558.  
  559.         //————    Get the parameter which contains the service identifier
  560.         //————    which we want to determine if it is supported
  561.     tVKind = kVUStringKind;
  562.     tErr = pReq->GetNthParam( 1, tParam, tVKind );
  563.     
  564.         //————    Make sure we have the right type of parameter
  565.     if( tParam == nil || tErr )
  566.     {
  567.         return;
  568.     }
  569.  
  570.     tSrvText = ((VUString*)tParam)->GetText();
  571.     if( tSrvText == nil )
  572.     {
  573.         return;
  574.     }
  575.  
  576.         //————    Scan through the Service objects, and inquire if any
  577.         //————    supports the indicated service
  578.     tLoop = new Loop( fServices );
  579.     if( tLoop )
  580.     {
  581.         while( tService = (Service*)(tLoop->GetNext()) )
  582.         {
  583.                 //————    Ask service object if it can do this service,
  584.             if( tService->CanDoService( tSrvText ) )
  585.             {
  586.                     //————    We have found a service object which can handle this
  587.                     //————    request type, return true to V.U.
  588.                 pReq->SetReturnValue( true );
  589.                 return;
  590.             }
  591.         }
  592.         delete tLoop;
  593.     }
  594.     
  595.         //————    We have looked through the entire list of service objects
  596.         //————    and have not found one which handles this request type
  597.         //————    return false to V.U.
  598.     pReq->SetReturnValue( false );
  599. }
  600.  
  601. //—————————————————————————————————————————————————————————————————————————————————————
  602. //    RequestDispatcher::GetToolName    
  603. //—————————————————————————————————————————————————————————————————————————————————————
  604. void
  605. RequestDispatcher::GetToolName( char* pText )
  606. {
  607.     short    tLength;
  608.     
  609.         //————    Get the Application name from the Low global CurApName
  610.     PLstrcpy( (StringPtr)pText, (StringPtr)CurApName );
  611.     p2cstr( (StringPtr)pText );
  612. }
  613.  
  614. //—————————————————————————————————————————————————————————————————————————————————————
  615. //    RequestDispatcher::GetToolVersionString    
  616. //—————————————————————————————————————————————————————————————————————————————————————
  617. void
  618. RequestDispatcher::GetToolVersionString( char* pText )
  619. {
  620.     VersResRecHdl    tVers;
  621.     short            tLength;
  622.     short            i;
  623.     char*            s;
  624.     char*            d;
  625.     
  626.     tVers = (VersResRecHdl)Get1Resource( 'vers', 1 );
  627.     if( tVers )
  628.     {
  629.         HLock( (Handle)tVers );
  630.             
  631.             //————    Set s to point at the length byte of the short version string
  632.         s = (*tVers)->versStr;
  633.  
  634.             //————    Advance s to the length byte of the long version string
  635.             //————    which begins just after the short version string
  636.         s += s[0] + 1;
  637.  
  638.             //————    Get the length of the long version string
  639.         tLength = s[0];
  640.  
  641.             //————    Copy the long version string into pText
  642.         d = pText;
  643.         s++;
  644.         for( i = 0; i < tLength; i++ )
  645.         {
  646.             *d++ = *s++;
  647.         }
  648.         *d = 0;        //————    Terminating Null character
  649.         
  650.         HUnlock( (Handle)tVers );
  651.         ReleaseResource( (Handle)tVers );
  652.     }
  653.     else
  654.     {
  655.         strcpy( pText, "Version string not availible." );
  656.     }
  657. }
  658.  
  659. //—————————————————————————————————————————————————————————————————————————————————————
  660. //    RequestDispatcher::ResetAllTimeOutCounters    
  661. //—————————————————————————————————————————————————————————————————————————————————————
  662. void
  663. RequestDispatcher::ResetAllTimeOutCounters()
  664. {
  665.     Loop        tLoop( fRequestQueue );
  666.     Request*    tReq;
  667.     
  668.     if( fReqBeingProcessed )
  669.     {
  670.         fReqBeingProcessed->ResetTimeOutCounter();
  671.     }
  672.     
  673.     while( tReq = (Request*)tLoop.GetNext() )
  674.     {
  675.         tReq->ResetTimeOutCounter();
  676.     }
  677.  
  678. }